import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Helius } from 'helius-sdk';
import { Connection, PublicKey, ParsedAccountData } from '@solana/web3.js';

@Injectable()
export class HeliusService {
  private readonly logger = new Logger(HeliusService.name);
  private readonly helius: Helius;
  private readonly connection: Connection;

  constructor(private configService: ConfigService) {
    const apiKey = this.configService.get<string>('HELIUS_API_KEY');
    if (!apiKey) {
      this.logger.warn('HELIUS_API_KEY not found, some features may not work');
    }

    this.helius = new Helius(apiKey || 'demo-key');
    this.connection = new Connection(
      this.configService.get<string>('RPC_URL') || 'https://api.devnet.solana.com'
    );
  }

  getConnection(): Connection {
    return this.connection;
  }

  isValidAddress(address: string): boolean {
    try {
      new PublicKey(address);
      return true;
    } catch {
      return false;
    }
  }

  async subscribeToAccount(address: string, callback: (accountInfo: any) => void): Promise<number> {
    try {
      const publicKey = new PublicKey(address);
      return this.connection.onAccountChange(publicKey, callback);
    } catch (error) {
      this.logger.error(`Failed to subscribe to account ${address}:`, error);
      throw error;
    }
  }

  async unsubscribeFromAccount(subscriptionId: number): Promise<void> {
    try {
      await this.connection.removeAccountChangeListener(subscriptionId);
    } catch (error) {
      this.logger.error(`Failed to unsubscribe from account:`, error);
      throw error;
    }
  }

  async getBalance(publicKey: string): Promise<number> {
    try {
      const balance = await this.connection.getBalance(new PublicKey(publicKey));
      return balance / 1e9; // Convert lamports to SOL
    } catch (error) {
      this.logger.error(`Failed to get balance for ${publicKey}:`, error);
      throw error;
    }
  }

  async getTokenAccounts(publicKey: string) {
    try {
      const accounts = await this.connection.getParsedTokenAccountsByOwner(
        new PublicKey(publicKey),
        { programId: new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA') }
      );

      return accounts.value.map(account => {
        const parsedData = account.account.data as ParsedAccountData;
        return {
          pubkey: account.pubkey.toString(),
          mint: parsedData.parsed.info.mint,
          amount: parsedData.parsed.info.tokenAmount.uiAmount,
          decimals: parsedData.parsed.info.tokenAmount.decimals,
        };
      });
    } catch (error) {
      this.logger.error(`Failed to get token accounts for ${publicKey}:`, error);
      throw error;
    }
  }

  /**
   * 获取代币持有者列表
   */
  async getTokenHolders(mint: string): Promise<any[]> {
    try {
      this.logger.log(`Getting token holders for mint: ${mint}`);
      
      // 使用 Solana RPC 获取代币持有者
      const mintPublicKey = new PublicKey(mint);
      const largestAccounts = await this.connection.getTokenLargestAccounts(mintPublicKey);
      
      // 过滤掉余额为0的账户
      const holders = largestAccounts.value.filter(account => 
        account.amount && parseInt(account.amount) > 0
      );
      
      this.logger.log(`Found ${holders.length} holders for token ${mint}`);
      return holders;
    } catch (error) {
      this.logger.error(`Failed to get token holders for ${mint}:`, error);
      throw error;
    }
  }

  async sendTransaction(transaction: string, signers?: string[]) {
    try {
      // Implementation for sending transactions via Helius
      this.logger.log('Sending transaction via Helius...');
      // TODO: Implement actual transaction sending
      return { signature: 'mock-signature' };
    } catch (error) {
      this.logger.error('Failed to send transaction:', error);
      throw error;
    }
  }

  async healthCheck(): Promise<boolean> {
    try {
      const slot = await this.connection.getSlot();
      return slot > 0;
    } catch (error) {
      this.logger.error('Helius service health check failed:', error);
      return false;
    }
  }
}
